package com.lyw.i05fair;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 公平锁和非公平锁
 *    1、非公平锁特点：
 *      - 效率高
 *      - 可能会有线程抢夺不到 CPU 执行权
 *    2、公平锁特点：
 *      - 效率会相对低一点
 *      - 大家都能执行到
 *  synchronized (隐式， 不需要我们手动释放锁) ；lock （显式，需要我们手动上锁） -》 这两个都是可重入锁
 *
 *  一个方法中在上锁的情况下调用了另一个也上锁的方法，并且没有出现等待情况（可重入锁）
 *
 *  可重入锁（又叫递归锁）：指的是以线程为单位，当一个线程获取对象锁之后，这个线程可以再次获取本对象上的锁，而其他的线程是不可以的。可重入锁的意义之一在于防止死锁。
 public class ReentranLockTest  implements Runnable{
   ReentrantLock lock = new ReentrantLock();
   public void get() {
     //第一个断点打再这  state 0->1 由无锁转入有锁
     lock.lock();
     System.out.println(Thread.currentThread().getId());
     set();
     //state 由1->0 至此同一线程的锁变成无锁状态
     lock.unlock();
   }
   public void set() {
     //第二个断点打在这 state 1->2
     lock.lock();
     System.out.println(Thread.currentThread().getId());
     //2->1
     lock.unlock();
   }
   @Override
   public void run() {
     get();
   }
   public static void main(String[] args) {
     ReentranLockTest ss = new ReentranLockTest();
     new Thread(ss).start();
   }
 }
 * @author lyw
 * @Date 2023/7/10-上午10:24
 */
class RLSale {

  // 默认创建一个非公平锁
  // 特点就是可能一个线程干完了所有的工作，不能均分给其他线程
  // private final ReentrantLock lock = new ReentrantLock(false);
  // 公平锁
  private final ReentrantLock lock = new ReentrantLock(true);
  private int num = 30;
  public void sale() {
    lock.lock();
    try {
      if (num > 0) {
        System.out.println(Thread.currentThread().getName() + "卖出了一张票，还有 " + --num + " 张");
      }
    } finally {
      lock.unlock();
    }
  }
}

public class FairDemo {
  public static void main(String[] args) {
    RLSale rlSale = new RLSale();
    for (int i = 0; i < 3; i++) {
      new Thread(() -> {
        for (int j = 0; j < 40; j++) {
          rlSale.sale();
        }
      }, "线程 " + i).start();
    }
  }
}
